﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DataModel
{

    public class Point
    {

        /**
         * x轴坐标 经度
         */
        double x;
        /**
         * y轴坐标 纬度
         */
        double y;
        public string carLocation { get; set; }
        public string dateTime { get; set; }
        public double speed { get; set; }
        public UInt64 sqlInt { get; set; }
        public Point setPoint(Point point)
        {
            this.x = point.getX();
            this.y = point.getY();
            return this;
        }

        public Point()
        {
        }

        public Point(string latLng)
        {
            string[] lt = latLng.Split(',');
            this.x = double.Parse(lt[1]);
            this.y = double.Parse(lt[0]);
        }

        public Point(float[] point)
        {
            this.x = point[0];
            this.y = point[1];
        }

        public Point(Double[] point)
        {
            this.x = point[0];
            this.y = point[1];
        }

        public Point(double x, double y)
        {
            this.x = x;
            this.y = y;
        }
        public Point(string x, string y)
        {
            this.x = double.Parse(x);
            this.y = double.Parse(y);
        }
        public double getX()
        {
            return x;
        }

        public void setX(double x)
        {
            this.x = x;
        }

        public double getY()
        {
            return y;
        }

        public void setY(double y)
        {
            this.y = y;
        }


    }


    public enum PointRelationEnum
    {
        POINT_IN_SCOPE = 1,
        POINT_OUT_SCOPE = 2,
        POINT_ON_BORDER = 3
    }


    public class OutInAreaLineAlarm
    {

        /// <summary>
        /// 路线偏移报警
        /// </summary>
        /// <param name="pt1"></param>
        /// <param name="ptLt"></param>
        /// <param name="range"></param>
        /// <returns></returns>
        public static bool CalcPointLineDistance(Point pt1, List<Point> ptLt, int range)
        {
            double jl = GetPointLineDistance(pt1, ptLt);
            if (jl > range)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        private static double earth_radius = 6378245.0;


        /// <summary>
        ///  判断点与多边形的关系，根据回转法，进出区域报警
        /// </summary>
        /// <param name="point"></param>
        /// <param name="points"></param>
        /// <returns></returns>
        public static PointRelationEnum PoinWithPolygon(Point point, List<Point> points)
        {
            double px = point.getX(), py = point.getY(), sum = 0;
            for (int i = 0, l = points.Count(), j = l - 1; i < l; j = i, i++)
            {
                double sx = points[i].getX(), sy = points[i].getY(), tx = points[j].getX(), ty = points[j].getY();
                // 点与多边形定点重合或多边形的边上
                if ((sx - px) * (px - tx) >= 0 && (sy - px) * (px - tx) >= 0
                        && (px - sx) * (ty - sy) == (py - sy) * (tx - sx))
                {
                    return PointRelationEnum.POINT_ON_BORDER;
                }
                // 点与相邻顶点连线的夹角
                double angle = Math.Atan2(sy - py, sx - px)
                        - Math.Atan2(ty - py, tx - px);
                // 确保夹角不超出取值范围（-π 到 π）
                if (angle >= Math.PI)
                {
                    angle = angle - Math.PI * 2;
                }
                else if (angle <= -Math.PI)
                {
                    angle = angle + Math.PI * 2;
                }
                sum += angle;
            }
            // 计算回转数并判断点和多边形的几何关系
            return Math.Round(sum / Math.PI) == 0 ? PointRelationEnum.POINT_OUT_SCOPE : PointRelationEnum.POINT_IN_SCOPE;
        }



        // 计算地球上两点的距离
        public static double GetTwoPointsDistance(Point pointA, Point pointB)
        {
            double distance = 0.0;
            if (pointA != null && pointB != null)
            {
                double x1 = 0.0, y1 = 0.0, x2 = 0.0, y2 = 0.0, dx1 = 0.0, dy1 = 0.0, dx2 = 0.0, dy2 = 0.0, a = earth_radius;
                x1 = GetLoop(pointA.getX(), -180, 180);
                y1 = GetRange(pointA.getY(), -90, 90);
                x2 = GetLoop(pointB.getX(), -180, 180);
                y2 = GetRange(pointB.getY(), -90, 90);
                dx1 =DegreeToRad(x1);
                dy1 = DegreeToRad(y1);
                dx2 = DegreeToRad(x2);
                dy2 = DegreeToRad(y2);
                distance = a * Math.Acos((Math.Sin(dy1) * Math.Sin(dy2) + Math.Cos(dy1) * Math.Cos(dy2) * Math.Cos(dx2 - dx1)));
                if (double.IsNaN(distance))
                {
                    distance = 0.0;
                }
            }
            return distance;
        }

        /** 计算地球上一点与区域边界的最小距离 **/
        private static double GetPointRangeDistance(Point point, List<Point> points)
        {
            double mindis = -1.0;
            if (point != null && points != null && points.Count() > 0)
            {
                double a = 0.0;
                double b = 0.0;
                double c = 0.0;
                double dis = 0.0;
                for (int i = 0; i < points.Count(); i++)
                {
                    if (i < points.Count() - 1)
                    {
                        a = GetTwoPointsDistance(points[i], points[i + 1]);
                        b = GetTwoPointsDistance(points[i], point);
                        c = GetTwoPointsDistance(points[i + 1], point);
                    }
                    else
                    {
                        a = GetTwoPointsDistance(points[i], points[0]);
                        b = GetTwoPointsDistance(points[i], point);
                        c = GetTwoPointsDistance(points[0], point);
                    }
                    dis = PointToLine(a, b, c);
                    if (mindis < 0)
                    {
                        mindis = dis;
                    }
                    else if (dis < mindis)
                    {
                        mindis = dis;
                    }
                }
            }
            return mindis;
        }

        /**
         * 计算地球上一点与一段道路的最小距离
         */

        public static double GetPointLineDistance(Point point, List<Point> points)
        {
            double mindis = -1.0;
            if (point != null && points != null && points.Count() > 0)
            {
                double a = 0.0;
                double b = 0.0;
                double c = 0.0;
                double dis = 0.0;
                for (int i = 0; i < points.Count() - 1; i++)
                {
                    a = GetTwoPointsDistance(points[i], points[i + 1]);
                    b = GetTwoPointsDistance(points[i], point);
                    c = GetTwoPointsDistance(points[i + 1], point);
                    if (b + c - a > 1)
                    {
                        dis = PointToLine(a, b, c);
                        if (mindis < 0)
                        {
                            mindis = dis;
                        }
                        else if (dis < mindis)
                        {
                            mindis = dis;
                        }
                    }
                    else
                    {
                        mindis = 1;
                    }


                }
            }
            return mindis;
        }


        /**
         * 计算点到线的距离
         */
        private static double PointToLine(double a, double b, double c)
        {
            double space = 0;
            if (c <= 0.000001 || b <= 0.000001)
            {
                space = 0;
                return space;
            }
            if (c * c >= a * a + b * b)
            {
                space = b;
                return space;
            }
            if (b * b >= a * a + c * c)
            {
                space = c;
                return space;
            }
            /** 半周长 */
            double p = (a + b + c) / 2;
            /** 海伦公式算面积 **/
            double s = Math.Sqrt(p * (p - a) * (p - b) * (p - c));
            space = 2 * s / a;
            return space;

        }

        // 经度用
        private static double GetLoop(double lng, double a, double b)
        {
            while (lng > b)
            {
                lng -= b - a;
            }
            while (lng < a)
            {
                lng += b - a;
            }
            return lng;
        }

        // 纬度用
        private static double GetRange(double lat, double a, double b)
        {
            if (a != 0)
            {
                lat = Math.Max(lat, a);
            }
            if (b != 0)
            {
                lat = Math.Min(lat, b);
            }
            return lat;
        }

        // 将弧度转化为度
        private static double DegreeToRad(double n)
        {
            return Math.PI * n / 180;
        }
    }


}
